package org.skatiger.jrove.renderer.html;

import java.io.IOException;
import java.util.Map;

import org.skatiger.jrove.ResponseWriter;
import org.skatiger.jrove.ViewContext;
import org.skatiger.jrove.component.JroveAttr;
import org.skatiger.jrove.component.UIComponent;
import org.skatiger.jrove.component.UIComponentBase;
import org.skatiger.jrove.component.foreach.ForeachStatus;
import org.skatiger.jrove.component.foreach.ForeachStatusIterator;
import org.skatiger.jrove.component.html.HtmlColumn;
import org.skatiger.jrove.renderer.Html;
import org.skatiger.jrove.renderer.HtmlRendererBase;
import org.skatiger.jrove.renderer.RendererUtils;
import org.skatiger.jrove.util.StringUtils;

public class HtmlDataTableRenderer extends HtmlRendererBase {
    @Override
    public void encodeBegin(ViewContext context, UIComponent component)
            throws IOException {
        super.encodeBegin(context, component);
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement(Html.TABLE_ELEM, component);
        renderId(context, component);
        RendererUtils.renderHtmlStandardAttributes(writer, component,
                Html.TABLE_ELEM_OPTIONAL_ATTRIBUTES);
        renderCaptionFacet(context, component);
    }

    protected void renderCaptionFacet(ViewContext context, UIComponent component)
            throws IOException {
        UIComponent captionFacet = (UIComponent) component.getAttributes().get(
                JroveAttr.CAPTION_FACET_NAME);
        if (captionFacet != null) {
            ResponseWriter writer = context.getResponseWriter();
            writer.startElement(Html.CAPTION_ELEM, captionFacet);
            //id
            //            String captionId = component.getClientId(context) + "_caption";
            //            RendererUtils.renderHtmlAttributeValue(context, Html.ID_ATTR, null,
            //                    captionId);
            captionFacet.encodeAll(context);
            writer.endElement(Html.CAPTION_ELEM);
        }
    }

    @Override
    public void encodeChildren(ViewContext context, UIComponent component)
            throws IOException {
        UIComponent[] columns = component
                .findChidlrenComponent(HtmlColumn.class);
        if (columns.length < 1) {
            return;
        }
        //render thead
        renderTHead(context, component, columns);
        //render tfoot
        renderTFoot(context, component, columns);

        renderTBody(context, component, columns);

    }

    public String getCurrentRowClasses(String[] rowClassArray, int current) {
        if (rowClassArray == null) {
            rowClassArray = new String[] { "" };//EMPTY classes
        }
        String currentRowClass = rowClassArray[0];
        if (rowClassArray.length > 1) {
            int idx = current % rowClassArray.length;//current start with 0
            currentRowClass = rowClassArray[idx];
        }
        return currentRowClass;
    }

    protected void renderTBody(ViewContext context, UIComponent table,
            UIComponent[] columns) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        Map<String, Object> attrs = context.getAttributes();

        ForeachStatusIterator it = (ForeachStatusIterator) table
                .getAttributes().get(JroveAttr.FOREACH_ITERATOR_PROPERTY_NAME);
        String var = (String) table.getAttributes().get(
                JroveAttr.FOREACH_VAR_NAME);
        String varStatus = (String) table.getAttributes().get(
                JroveAttr.FOREACH_VAR_STATUS_NAME);
        if (it.hasNext()) {// if not facet name in component,render nothing
            String[] rowClassArray;
            {
                String rowClasses = (String) table.getAttributes().get(
                        JroveAttr.ROW_CLASSES_NAME);
                if (StringUtils.isNotEmpty(rowClasses)) {
                    rowClassArray = rowClasses.split(",");
                } else {
                    rowClassArray = new String[] { "" };//EMPTY classes
                }
            }
            Object previousVar = null;
            Object previousVarStatus = null;

            {//capture previous Object
                if (var != null) {
                    previousVar = attrs.get(var);
                }
                if (varStatus != null) {
                    previousVarStatus = attrs.get(varStatus);
                }
            }

            writer.startElement(Html.TBODY_ELEM, table);
            int i = 0;
            while (it.hasNext()) {
                String styleClass = getCurrentRowClasses(rowClassArray, i);
                renderRow(context, table, columns, var, varStatus, it,
                        styleClass);
                i++;
            }
            writer.endElement(Html.TBODY_ELEM);

            {//restore previous Object
                if (var != null) {
                    if (previousVar != null) {
                        attrs.put(var, previousVar);
                    } else {
                        attrs.remove(var);
                    }
                }
                if (varStatus != null) {
                    if (previousVarStatus != null) {
                        attrs.put(varStatus, previousVarStatus);
                    } else {
                        attrs.remove(varStatus);
                    }
                }
            }
        }
    }

    protected void renderRow(ViewContext context, UIComponent table,
            UIComponent[] columns, String var, String varStatus,
            ForeachStatusIterator it, String styleClass) throws IOException {
        Object _item = it.next();
        {//put table
            if (var != null && !var.trim().isEmpty()) {
                context.getAttributes().put(var, _item);
            }

            if (varStatus != null && !varStatus.trim().isEmpty()) {
                ForeachStatus _status = it.getStatus();
                context.getAttributes().put(varStatus, _status);
            }
        }
        _renderRow(context, table, columns, _item, styleClass);
    }

    protected void _renderRow(ViewContext context, UIComponent table,
            UIComponent[] columns, Object _item, String styleClass)
            throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement(Html.TR_ELEM, table);
        RendererUtils.renderHtmlAttributeValue(writer, Html.CLASS_ATTR,
                "rowClasses", styleClass);
        //renderer columns start
        renderColumns(context, table, columns);
        //renderer columns end
        writer.endElement(Html.TR_ELEM);

    }

    protected void renderColumns(ViewContext context, UIComponent table,
            UIComponent[] columns) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        for (UIComponent column : columns) {
            writer.startElement(Html.TD_ELEM, column);
            RendererUtils.renderHtmlStandardAttributes(writer, column);
            column.encodeAll(context);
            context.getResponseWriter().endElement(Html.TD_ELEM);
        }
    }

    protected void renderTFoot(ViewContext context, UIComponent table,
            UIComponent[] columns) throws IOException {
        renderTableInnerElement(context, table, columns,
                JroveAttr.FOOTER_FACET_NAME, Html.TFOOT_ELEM, Html.TD_ELEM);
    }

    protected void renderTHead(ViewContext context, UIComponent table,
            UIComponent[] columns) throws IOException {
        renderTableInnerElement(context, table, columns,
                JroveAttr.HEADER_FACET_NAME, Html.THEAD_ELEM, Html.TH_ELEM);
    }

    private void renderTableInnerElement(ViewContext context,
            UIComponent table, UIComponent[] columns, String facetName,
            String innerElement, String elementTag) throws IOException {
        UIComponent[] columnFacets = getColumnFacet(columns, facetName);
        UIComponent tableFacet = table.getFacet(facetName);
        ResponseWriter writer = context.getResponseWriter();
        boolean hasFacet = columnFacets.length > 0 || tableFacet != null;
        if (hasFacet) {
            writer.startElement(innerElement, null);
            if (innerElement.equals(Html.THEAD_ELEM)) {
                renderTableFacet(context, tableFacet, columns.length);
            }
            if (columnFacets.length > 0) {// if not facet name in component,render nothing
                writer.startElement(Html.TR_ELEM, null);
                for (int i = 0; i < columns.length; i++) {
                    UIComponent column = columnFacets[i];
                    String facetClassName = facetName + Html.CLASS_ATTR;
                    String facetStyleClass = (String) column.getAttributes()
                            .get(facetClassName);
                    renderColumnFacet(context, columnFacets[i],
                            facetStyleClass, elementTag);
                }
                writer.endElement(Html.TR_ELEM);
            }
            if (innerElement.equals(Html.TFOOT_ELEM)) {
                renderTableFacet(context, tableFacet, columns.length);
            }
            writer.endElement(innerElement);
        }
    }

    private void renderTableFacet(ViewContext context, UIComponent tableFacet,
            int columnLength) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        if (tableFacet != null) {// has table facet
            writer.startElement(Html.TR_ELEM, tableFacet);
            UIComponent[] tableFacetColumns = tableFacet
                    .findChidlrenComponent(HtmlColumn.class);
            if (tableFacetColumns.length > 0) {// table facets has column  children
                for (UIComponent column : tableFacetColumns) {
                    writer.startElement(Html.TH_ELEM, column);
                    RendererUtils.renderHtmlStandardAttributes(writer, column,
                            Html.TH_ELEM_OPTIONAL_ATTRIBUTES);
                    writer.endElement(Html.TH_ELEM);
                }
            } else {//table facets not column children
                writer.startElement(Html.TH_ELEM, null);
                if (columnLength > 1) {
                    RendererUtils.renderHtmlAttributeValue(writer,
                            Html.COLSPAN_ATTR, Html.COLSPAN_ATTR, columnLength);
                }
                tableFacet.encodeAll(context);
                writer.endElement(Html.TH_ELEM);
            }
            writer.endElement(Html.TR_ELEM);
        }
    }

    private void renderColumnFacet(ViewContext context, UIComponent facet,
            String facetClass, String htmlTag) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement(htmlTag, null);
        if (facetClass != null) {
            RendererUtils.renderHtmlAttributeValue(writer, Html.CLASS_ATTR,
                    null, facetClass);
        }
        if (facet != null) {
            facet.encodeAll(context);
        }
        writer.endElement(htmlTag);
    }

    protected UIComponent[] getColumnFacet(UIComponent[] columns,
            String facetName) {
        boolean hasFacet = false;
        UIComponent[] facets = new UIComponent[columns.length];
        for (int i = 0; i < columns.length; i++) {
            UIComponent column = columns[i];
            UIComponent facet = (UIComponent) column.getAttributes().get(
                    facetName);
            if (facet != null) {
                facets[i] = facet;
                hasFacet = true;
            } else {
                facets[i] = EMPTY_COMPONENT;
            }
        }
        if (!hasFacet) {
            return new UIComponent[0];
        }
        return facets;
    }

    @Override
    public void encodeEnd(ViewContext context, UIComponent component)
            throws IOException {
        super.encodeEnd(context, component);
        ResponseWriter writer = context.getResponseWriter();
        writer.endElement(Html.TABLE_ELEM);
    }

    @Override
    public boolean isRendersChildren() {
        return true;
    }

    private static UIComponent EMPTY_COMPONENT = new UIComponentBase() {
    };
}
